/*
 * TraceFunction.c
 *
 *  Created on: 2012/08/03
 *      Author: guanxiaoying
 */
#include "../tracedef.h"
#include "../../table/core_table.h"
#include "trace_cmd.h"
#define TRFUNC_PATH_COLLECTED  0x00000001UL
#define TRFUNC_TRACED  0x00000002UL
#define TRFUNC_STARTED  0x00000004UL
#define TRFUNC_TRACING  0x00000008UL

/* check whether the PATHs have been created */
BOOL Tr_FuncIsPathCollected( AST astFunction ){
	U4  attr = stTrFunctionAccess.attribute.get( astFunction );
	return ( attr & TRFUNC_PATH_COLLECTED ) != 0;
}
/* mark the function: the PATHs have been created */
VOID Tr_FuncSetPathCollected( AST astFunction ){
	U4  attr = stTrFunctionAccess.attribute.get( astFunction );
	attr |= TRFUNC_PATH_COLLECTED;
	stTrFunctionAccess.attribute.set( astFunction, attr );
}
/* delete mark: the PATHs have been created */
VOID Tr_FuncDeletePathCollected( AST astFunction ){
	U4  attr = stTrFunctionAccess.attribute.get( astFunction );
	attr &= ~TRFUNC_PATH_COLLECTED;
	stTrFunctionAccess.attribute.set( astFunction, attr );
}
/* whether the function is being tracing */
BOOL Tr_FuncIsInTracing( AST astFunction ){
	U4  attr = stTrFunctionAccess.attribute.get( astFunction );
	return attr&TRFUNC_TRACING;
}
/* mark the function : the function is being tracing  */
VOID Tr_FuncSetInTracing( AST astFunction ){
	U4  attr = stTrFunctionAccess.attribute.get( astFunction );
	attr |= TRFUNC_TRACING;
	attr &= ~TRFUNC_STARTED;
	attr &= ~TRFUNC_TRACED;
	stTrFunctionAccess.attribute.set( astFunction, attr );
}
/* whether the function has been traced */
BOOL Tr_FuncIsTraced( AST astFunction ){
	U4  attr = stTrFunctionAccess.attribute.get( astFunction );
	return attr&TRFUNC_TRACED;
}
/* mark the function : the function  has been traced */
VOID Tr_FuncSetTraced( AST astFunction ){
	U4  attr = stTrFunctionAccess.attribute.get( astFunction );
	attr |= TRFUNC_TRACED;
	attr &= ~TRFUNC_STARTED;
	attr &= ~TRFUNC_TRACING;
	stTrFunctionAccess.attribute.set( astFunction, attr );
}
/* whether the function trace started  */
BOOL Tr_FuncIsStarted( AST astFunction ){
	U4  attr = stTrFunctionAccess.attribute.get( astFunction );
	return (attr&TRFUNC_STARTED)!=0 ;
}
/* mark the function: the function trace started  */
VOID Tr_FuncSetStarted( AST astFunction ){
	U4  attr = stTrFunctionAccess.attribute.get( astFunction );
	attr |= TRFUNC_STARTED;
	attr &= ~TRFUNC_TRACED;
	attr &= ~TRFUNC_TRACING;
	stTrFunctionAccess.attribute.set( astFunction, attr );
}
/* delete all trace mark of the function: the function trace started  */
VOID Tr_FuncDeleteTracingStatus( AST astFunction ){
	U4  attr = stTrFunctionAccess.attribute.get( astFunction );
	attr &= ~(TRFUNC_STARTED|TRFUNC_TRACED|TRFUNC_TRACING);
	stTrFunctionAccess.attribute.set( astFunction, attr );
}
/* enter into a callee function */
S4 Tr_FunctionEntry( AST astFunction ){
	S4 result = TRACEEXIT_SUCCESS;

	stTrFunctionAccess.function.set( astFunction, astFunction );
	if( Tr_FuncIsTraced(astFunction) ){
		/* has been traced, do not enter into callee */
		return result;
	}
	if( stTrFunctionAccess.pathInfo.get( astFunction ) == 0 ){
		/* has been defined, no function body. do not enter into callee */
		return result;
	}
	/* delete TRFUNC_TRACED and TRFUNC_TRACING */
	/* add TRFUNC_STARTED */
	Tr_FuncSetStarted(astFunction);
	if( stCmdTraceOption.ulCmdEvent & EVENT_CMDLIST_ENTRY_PREV ){
		if( stCmdTraceOption.pCallBackFunction != NULL ){
			stCmdTraceOption.pCallBackFunction( LinkFunction.getFunctionEntry( astFunction ),
					EVENT_CMDLIST_ENTRY_PREV );
		}
	}
	/* push caller function status */
	result = Tr_StkFuncProcess( STACK_PUSH );
	if( result != TRACEEXIT_SUCCESS ){
		return result;
	}
	stCmdCurrTraceInfo.astTable  = 0;
	stCmdCurrTraceInfo.astNext = 0;
	stCmdCurrTraceInfo.astLoop = 0;
	stCmdCurrTraceInfo.astPathParam = Tr_PathParamNewPathParam();
	stCmdCurrTraceInfo.astFunction = astFunction;
	stCmdCurrTraceInfo.astPathStkBottom = Tr_StkGetTopPath();
	stCmdCurrTraceInfo.astLoopExitBottom = Tr_StkGetTopExit();
	stCmdCurrTraceInfo.astPath = stTrFunctionAccess.pathInfo.get( astFunction );
	stCmdCurrTraceInfo.astPathNext = stCmdPathInfoAccess.pathOut.get( stCmdCurrTraceInfo.astPath );
	stCmdCurrTraceInfo.loopFlg = LOOP_FLG_NONE;

	if( stCmdTraceOption.ulCmdEvent & EVENT_CMDLIST_ENTRY_POST ){
		if( stCmdTraceOption.pCallBackFunction != NULL ){
			stCmdTraceOption.pCallBackFunction( LinkFunction.getFunctionEntry( astFunction ),
					EVENT_CMDLIST_ENTRY_PREV );
		}
	}
	return TRACEEXIT_END;
}
/* returned from a callee function */
S4 Tr_FunctionExit( AST astFunction ){
	S4 result = TRACEEXIT_SUCCESS;
	/* delete TRFUNC_STARTED and TRFUNC_TRACING */
	/* add TRFUNC_TRACED */
	Tr_FuncSetTraced(astFunction);
	if( stCmdTraceOption.ulCmdEvent & EVENT_CMDLIST_EXIT_PREV ){
		if( stCmdTraceOption.pCallBackFunction != NULL ){
			stCmdTraceOption.pCallBackFunction( astFunction, EVENT_CMDLIST_EXIT_PREV );
		}
	}
	/* pop caller function status */
	result = Tr_StkFuncProcess( STACK_PULL );
	if( result != TRACEEXIT_SUCCESS ){
		return result;
	}
	if( stCmdTraceOption.ulCmdEvent & EVENT_CMDLIST_EXIT_POST ){
		if( stCmdTraceOption.pCallBackFunction != NULL ){
			stCmdTraceOption.pCallBackFunction( astFunction, EVENT_CMDLIST_EXIT_POST );
		}
	}
	return result;
}
/* get the callee function of a ASM_CMD_CALL COMMAND */
AST  Tr_FunctionGetCallee( AST astCmdList ){
	AST astOperand = stCmdListAccess.leftOperand.get( stCmdCurrTraceInfo.astTable );
	if( stOperandAccess.kind.get( astOperand ) == OPERAND_FUNCTION ){
		return stOperandAccess.parameter.get( astOperand );
	}
	return 0;
}
/* begin tracing the root function */
S4 Tr_FunctionTraceAsEntry( AST astFunction ){
	S4 result = TRACEEXIT_SUCCESS;

	if( Tr_FuncIsTraced(astFunction) ){
		return result;
	}
	Tr_StkClearExit();
	Tr_StkClearPath();
	Tr_StkClearFunction();
	Tr_StkClearLoop();
	Tr_VarBlkClear();
	Tr_VariClear();

	if( stCmdTraceOption.ulCmdEvent & EVENT_CMDLIST_ENTRY_PREV ){
		if( stCmdTraceOption.pCallBackFunction != NULL ){
			stCmdTraceOption.pCallBackFunction( astFunction, EVENT_CMDLIST_ENTRY_PREV );
		}
	}
	stCmdCurrTraceInfo.astPath = stTrFunctionAccess.pathInfo.get( astFunction );
	stCmdCurrTraceInfo.astPathNext = stCmdPathInfoAccess.pathOut.get( stCmdCurrTraceInfo.astPath );
	stCmdCurrTraceInfo.astFunction = astFunction;
	stCmdCurrTraceInfo.loopFlg = LOOP_FLG_NONE;
	stCmdCurrTraceInfo.astLoop = 0;
	stCmdCurrTraceInfo.astLoopExitBottom = 0;
	stCmdCurrTraceInfo.astPathStkBottom = 0;
	/* new block */
	stCmdCurrTraceInfo.astPathParam = Tr_PathParamNewPathParam();
	stCmdCurrTraceInfo.astTable = 0;
	stCmdCurrTraceInfo.astNext = 0;


	result = Tr_PathLoop();
	if( stCmdTraceOption.ulCmdEvent & EVENT_CMDLIST_EXIT_POST ){
		if( stCmdTraceOption.pCallBackFunction != NULL ){
			stCmdTraceOption.pCallBackFunction( astFunction, EVENT_CMDLIST_EXIT_POST );
		}
	}
	Tr_StkClearExit();
	Tr_StkClearPath();
	Tr_StkClearFunction();
	Tr_StkClearLoop();
	Tr_VarBlkClear();
	Tr_VariClear();
	/* delete TRFUNC_STARTED and TRFUNC_TRACING */
	/* add TRFUNC_TRACED */
	Tr_FuncSetTraced(astFunction);
	return result;
}
VOID Tr_FuncMergeReturnValue(  AST astFunction, TRVALUESCP * stVarScope ){
	TRVALUESCP stOld;
	stTrFunctionAccess.getValueScope( astFunction , &stOld );
	Tr_ScpMergeOrOr( &stOld, stVarScope, &stOld );
	stTrFunctionAccess.setValueScope( astFunction , &stOld );
}
VOID Tr_FuncSetReturnValue(  AST astFunction, TRVALUESCP * stVarScope ){
	stTrFunctionAccess.setValueScope( astFunction , stVarScope );
}
